import {StrUtil} from '../../utils/StrUtil.js';

export class NbGoStep {
    /**
     * @param {object} options
     * @param {string} options.key 步骤唯一键
     * @param {string} options.name 步骤名称
     * @param {string} options.description 步骤描述
     * @param {number} [options.timeoutMs] 超时时间，默认 10 分钟
     */
    constructor({key, name, description, timeoutMs = 600_000}) {
        this.key = key;
        this.name = name;
        this.description = description || name;
        this.timeoutMs = timeoutMs;
    }

    /**
     * 执行步骤
     * @param {object} context
     * @param {number} stepIndex 从 1 开始的步骤编号
     * @returns {Promise<void>}
     */
    async run(context, stepIndex) {
        const {logger, stateManager} = context;
        await stateManager.init();
        const state = stateManager.getStep(this.key);
        const skipInfo = await this.shouldSkip(context, state);
        if (skipInfo?.skip) {
            logger.step(stepIndex, `${this.name}（跳过）`);
            if (StrUtil.notNull(skipInfo.reason)) {
                logger.info(`${this.name} 跳过原因：${skipInfo.reason}`);
            }
            if (!state || state.status !== 'completed') {
                await stateManager.updateStep(this.key, 'skipped', skipInfo.metadata);
            }
            return;
        }
        logger.step(stepIndex, this.description);
        try {
            const metadata = await this.execute(context);
            await stateManager.updateStep(this.key, 'completed', metadata);
            logger.success(`${this.name} 完成`);
        } catch (error) {
            await stateManager.updateStep(this.key, 'failed', {
                reason: error.message
            });
            throw error;
        }
    }

    /**
     * 判断是否跳过执行
     * @param {object} context
     * @param {{status:string,metadata?:object}|null} state
     * @returns {Promise<{skip:boolean,reason?:string,metadata?:object}>}
     */
    // eslint-disable-next-line no-unused-vars
    async shouldSkip(context, state) {
        return {skip: false};
    }

    /**
     * 执行具体逻辑
     * @param {object} context
     * @returns {Promise<object|undefined>}
     */
    // eslint-disable-next-line no-unused-vars
    async execute(context) {
        throw new Error(`${this.name} execute 方法未实现`);
    }
}
